package gui;

import java.awt.Component;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.ArrayList;
import java.util.List;

import javax.swing.AbstractAction;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.JToggleButton;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import javax.swing.text.JTextComponent;

import com.google.common.collect.ContiguousSet;
import com.google.common.collect.DiscreteDomain;
import com.google.common.collect.Range;

/**
 * A button which opens a popup menu allowing the insertion of a charecter from a range
 * into a text component.
 * 
 * @author Joshua Lockerman
 */
public class CharacterInsertionButton extends JToggleButton {
    
    private static class CharDomain extends DiscreteDomain<Character> {
        
        @Override
        public long distance(Character start, Character end)
        {
            return end - start;
        }
        
        @Override
        public Character next(Character value)
        {
            return (char) (value + 1);
        }
        
        @Override
        public Character previous(Character value)
        {
            return (char) (value - 1);
        }
        
    }
    
    private static CharDomain charDomain = new CharDomain();
    
    private static final int COLUMN_COUNT = 5;
    
    private final JPopupMenu popup;
    JTextComponent textComponent;
    
    public CharacterInsertionButton(JTextComponent textComponent, Range<Character>... ranges)
    {
        this.textComponent = textComponent;
        
        String name = "" + ranges[0].lowerEndpoint() + " - "
                + ranges[ranges.length - 1].upperEndpoint();
        setText(name);

        popup = new JPopupMenu();
        
        List<Component> buttons = createButtons(ranges);
        popup.setLayout(new GridLayout(0, COLUMN_COUNT));
        for(Component button : buttons) {
            popup.add(button);
        }
        
        addItemListener(new ItemListener() {
            @Override
            public void itemStateChanged(ItemEvent e)
            {
                if(e.getStateChange() == ItemEvent.SELECTED) {
                    popup.show(CharacterInsertionButton.this, CharacterInsertionButton.this.getX()
                            - (popup.getWidth() / 2),
                            CharacterInsertionButton.this.getY() - popup.getHeight());
                    popup.setSelected(popup.getComponent(0));
                }
                else {
                    //popup.setVisible(false);
                }
            }
        });
        
        popup.addPopupMenuListener(new PopupMenuListener() {
            @Override
            public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
            }
            
            @Override
            public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
                setSelected(false);
                //throw new RuntimeException();
            }
            
            @Override
            public void popupMenuCanceled(PopupMenuEvent e) {
                setSelected(false);
            }
        });
        
        // TODO 
    }
    
    /**
     * @param ranges
     */
    private List<Component> createButtons(Range<Character>... ranges)
    {
        ArrayList<Component> buttons = new ArrayList<Component>();
        for(int i = 0; i < ranges.length; i++) {
            ContiguousSet<Character> set = ranges[i].asSet(charDomain);
            for(Character c : set) {
                buttons.add(createButton(c));
            }
        }
        return buttons;
    }
    
    private Component createButton(final Character c)
    {
        final JMenuItem button = new JMenuItem();
        button.setAction(new AbstractAction(c.toString()) {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                popup.setVisible(false);
                textComponent.replaceSelection(c.toString());
            }
        });
        return button;
    }
}
